﻿using System.Collections.Concurrent;
using System;

namespace Lypshare.Net.Server
{
	/// <summary>
	/// Client manager.
	/// </summary>
	/// <exception cref='ArgumentNullException'>
	/// Is thrown when an argument passed to a method is invalid because it is <see langword="null" /> .
	/// </exception>
	/// <exception cref='InvalidOperationException'>
	/// Is thrown when an operation cannot be performed.
	/// </exception>
    public static class ClientManager
    {
        // --------------------------------------------------------
        // Static Variables
        // --------------------------------------------------------


        /// <summary>
        /// The _ clients.
        /// </summary>
        private static ConcurrentDictionary<int, Client> _Clients
            = new ConcurrentDictionary<int, Client>();


        /// <summary>
        /// The _ validator.
        /// </summary>
        private static IValidator _Validator = null;


        // --------------------------------------------------------
        // Static Properties
        // --------------------------------------------------------


        /// <summary>
        /// Gets or sets the validator.
        /// </summary>
        /// <value>
        /// The validator.
        /// </value>
        public static IValidator Validator
        {
            get { return _Validator; }
            set { _Validator = value; }

        } // Property: Validator


        /// <summary>
        /// Gets a value indicating whether this instance has validator.
        /// </summary>
        /// <value>
        /// <c>true</c> if this instance has validator; otherwise, <c>false</c>.
        /// </value>
        public static bool HasValidator
        {
            get { return _Validator != null; }

        } // Property: HasValidator


        // --------------------------------------------------------
        // Static Functions
        // --------------------------------------------------------


        /// <summary>
        /// Contains the specified clientId.
        /// </summary>
        /// <param name='clientId'>
        /// If set to <c>true</c> client identifier.
        /// </param>
        public static bool Contains(int clientId)
        {
            return _Clients.ContainsKey(clientId);

        } // Contains


        /// <summary>
        /// Auth the specified username and password.
        /// </summary>
        /// <param name='username'>
        /// If set to <c>true</c> username.
        /// </param>
        /// <param name='password'>
        /// If set to <c>true</c> password.
        /// </param>
        /// <exception cref='ArgumentNullException'>
        /// Is thrown when an argument passed to a method is invalid because it is <see langword="null" /> .
        /// </exception>
        public static bool Auth(String username, String password)
        {
            if (username == null) throw new ArgumentNullException("username");
            if (password == null) throw new ArgumentNullException("password");

            if (HasValidator)
            {
                if (!Validator.Auth(username, password))
                    return false;

            } // if (HasValidator)

            return true;

        } // Auth


        /// <summary>
        /// Add the specified client.
        /// </summary>
        /// <param name='client'>
        /// Client.
        /// </param>
        /// <exception cref='ArgumentNullException'>
        /// Is thrown when an argument passed to a method is invalid because it is <see langword="null" /> .
        /// </exception>
        /// <exception cref='InvalidOperationException'>
        /// Is thrown when an operation cannot be performed.
        /// </exception>
        public static void Add(Client client)
        {
            if(client == null)
                throw new ArgumentNullException("client");
			
			if(Contains(client.Id))
				throw new InvalidOperationException(
					"Client already exist in client manager.");
			
            client.Disconnected += 
                (sender) => Remove(client);

            _Clients.TryAdd(
                client.Id, client);

        } // Add


        /// <summary>
        /// Remove the specified client.
        /// </summary>
        /// <param name='client'>
        /// Client.
        /// </param>
        /// <exception cref='ArgumentNullException'>
        /// Is thrown when an argument passed to a method is invalid because it is <see langword="null" /> .
        /// </exception>
        public static void Remove(Client client)
        {
            if (client == null)
                throw new ArgumentNullException("client");

            _Clients.TryRemove(
                client.Id, out client);

        } // Remove


        /// <summary>
        /// Get the specified clientId.
        /// </summary>
        /// <param name='clientId'>
        /// Client identifier.
        /// </param>
        /// <exception cref='InvalidOperationException'>
        /// Is thrown when an operation cannot be performed.
        /// </exception>
        public static Client Get(int clientId)
        {
            if (!Contains(clientId))
                throw new InvalidOperationException(
                    "Client with id " + clientId + " is unknown.");

            return _Clients[clientId];

        } // Get

    } // static class ClientManager
} // namespace Lypshare.Net.Server